﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using xn;
using System.Windows.Threading;
using System.IO;
using System.Drawing;
using System.Drawing.Imaging;
using DX = Microsoft.DirectX.DirectSound;
using System.Media;
using NAudio;
using NAudio.Wave;


namespace WpfApplication1
{
    /// <summary>
    /// Interaktionslogik für Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private Context context;
        private DepthGenerator depth;
        private UserGenerator userGen;
        private ImageGenerator imageGen;
        private WaveOut waveOut;
        private Bitmap bitmap;
        private bool started = false;
        private SineWaveProvider32 sinWaveProvider;
  
        public Window1()
        {
            InitializeComponent();
        }

        private unsafe void DrawImageData()
        {
            // Get information about the depth image
            DepthMetaData depthMD = new DepthMetaData();
            System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, this.bitmap.Width, this.bitmap.Height);
            BitmapData data = this.bitmap.LockBits(rect, ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            depth.GetMetaData(depthMD);
            ushort* pDepth = (ushort*)this.depth.GetDepthMapPtr().ToPointer();
            // Go over the depth image and set the bitmap we're copying to based on our depth value.
            for (int y = 0; y < depthMD.YRes; ++y)
            {
                byte* pDest = (byte*)data.Scan0.ToPointer() + y * data.Stride;
                for (int x = 0; x < depthMD.XRes; ++x, ++pDepth, pDest += 3)
                {
                    // Change the color of the bitmap based on the depth value. You can make this
                    // whatever you want, my particular version is not that pretty.
                    pDest[0] = (byte)(*pDepth >> 2);
                    pDest[1] = (byte)(*pDepth >> 3);
                    pDest[2] = (byte)(*pDepth >> 4);
                }
            }
            this.bitmap.UnlockBits(data);
            // Update the image to have the bitmap image we just copied
            image1.Source = getBitmapImage(bitmap);
        }

        public void GetUserPositions()
        {
            Point3D userPosition;
            SceneMetaData userPixel = null;
            if (userGen.GetUsers().Length > 0)
            {
                userPosition = userGen.GetCoM(userGen.GetUsers()[0]);
                userPixel = userGen.GetUserPixels(userGen.GetUsers()[0]);
                textBox1.AppendText("User: " + userGen.GetUsers()[0] + " von " + userGen.GetUsers().Length + " | x: " + userPosition.X + " | y: " + userPosition.Y + " | z: " + userPosition.Z + "\n");
            }
        }

        public static BitmapImage getBitmapImage(Bitmap bitmap)
        {
            MemoryStream ms = new MemoryStream();
            bitmap.Save(ms, ImageFormat.Png);
            ms.Position = 0;
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            ms.Seek(0, SeekOrigin.Begin);
            bi.StreamSource = ms;
            bi.EndInit();
            return bi;
        }

        private void InitKinect()
        {
            try
            {
                // Initialize the context from the configuration file
                this.context = new Context(@"..\..\data\openniconfig.xml");
                // Get the depth generator from the config file.
                this.depth = context.FindExistingNode(NodeType.Depth) as DepthGenerator;
                if (this.depth == null)
                    throw new Exception(@"Error in Data\openniconfig.xml. No depth node found.");
                this.userGen = context.FindExistingNode(NodeType.User) as UserGenerator;
                if (this.userGen == null)
                    throw new Exception(@"Error in Data\openniconfig.xml. No user node found.");
                this.imageGen = context.FindExistingNode(NodeType.Image) as ImageGenerator;
                if (this.imageGen == null)
                    throw new Exception(@"Error in Data\openniconfig.xml. No image node found.");
                MapOutputMode mapMode = this.depth.GetMapOutputMode();
                this.bitmap = new Bitmap((int)mapMode.nXRes, (int)mapMode.nYRes, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
            }
            catch (Exception ex)
            {
                MessageBox.Show("Error initializing OpenNI.");
                MessageBox.Show(ex.Message);
                this.Close();
            }
            DispatcherTimer dispatcherTimer = new DispatcherTimer();
            dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
            dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 10);
            dispatcherTimer.Start();
            started = true;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            
        }

        private void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            try
            {
                this.context.WaitAndUpdateAll();
            }
            catch (Exception)
            {
            }
            DrawImageData();
            GetUserPositions();
        }



        private void button1_Click(object sender, RoutedEventArgs e)
        {
            if (!started)
            {
                textBox1.AppendText("starting... \n");
                InitKinect();
                textBox1.AppendText("Kinect connected \n");
                button1.IsEnabled = !started;
            }
        }

        private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
        {

        }

        private void image1_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {

        }

        private void StartStopSineWave()
        {
            
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            if (waveOut == null)
            {
                sinWaveProvider = new SineWaveProvider32();
                sinWaveProvider.SetWaveFormat(16000, 1); // 16kHz mono
                sinWaveProvider.Frequency = 1000;
                sinWaveProvider.Amplitude = 0.25f;
                waveOut = new WaveOut();
                waveOut.Init(sinWaveProvider);
                waveOut.Play();
            }
            else
            {
                waveOut.Stop();
                waveOut.Dispose();
                waveOut = null;
            }
        }

        private void slider1_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {

                if (sinWaveProvider == null)
                {
                    sinWaveProvider = new SineWaveProvider32();
                }
                sinWaveProvider.SetWaveFormat(16000, 2); // 16kHz mono
                sinWaveProvider.Frequency = (float)e.NewValue;
                sinWaveProvider.Amplitude = 0.25f;
                waveOut = new WaveOut();
                try
                {
                    waveOut.Init(sinWaveProvider);
                    waveOut.Play();
                }
                catch (Exception ex)
                {
                    textBox1.AppendText(ex.Message);
                }
                
           

        }


    }
}
